#include "gfx.h"
#include <stdlib.h>
#include <string.h>

//static u16* buffer;
static int rotation;
static int _width, _height; // Display w/h as modified by current rotation
static int  cursor_x, cursor_y;
//static int textbgcolor;
static int textcolor;
static int textsize;
static int wrap;   // If set, 'wrap' text at right edge of display
static int _cp437; // If set, use correct CP437 charset (default is off)
tGFXfont *gfxFont;

void gfx_Init(void) {
//  	int bytes = tft_Width() * tft_Height() * 2;
//  	if((buffer = (u16*)malloc(bytes))) {
//    		memset(buffer, 0, bytes);
//  	}

  	_width    = gfxWIDTH;
  	_height   = gfxHEIGHT;
  	rotation  = 0;
  	cursor_y  = 0;
  	cursor_x  = 0;
  	textsize  = 1;
  	textcolor = clWhite;
  	//textbgcolor = clWhite;
  	wrap      = pdTRUE;
  	_cp437    = pdFALSE;
  	gfxFont   = NULL;
}

//void gfx_Finish(void) {
//	if(buffer) free(buffer);
//}
//
//u16* gfx_getBuffer(void) {
//	return buffer;
//}

//static void fillScreen(int color) {
//  	if(buffer) {
//   	 	u8 hi = color >> 8, lo = color & 0xFF;
//    	if(hi == lo) {
//      		memset(buffer, lo, gfxWIDTH * gfxHEIGHT * 2);
//    	} else {
//      		int i, pixels = gfxWIDTH * gfxHEIGHT;
//      		for(i=0; i<pixels; i++) buffer[i] = color;
//    	}
//  	}
//}

void gfx_SetRotation(u8 x) {
  	rotation = (x & 3);
  	switch(rotation) {
   	case 0:
   	case 2:
    	_width  = gfxWIDTH;
    	_height = gfxHEIGHT;
    	break;
   	case 1:
   	case 3:
    	_width  = gfxHEIGHT;
    	_height = gfxWIDTH;
    	break;
  	}
	tft_SetRotation(rotation);
}

u8 gfx_GetRotation(void) {
  	return rotation;
}

//##################################################################################################################
// PRIMITIVES
//##################################################################################################################
#define gfx_DrawPixel tft_DrawPixel
//void gfx_DrawPixel(int x, int y, int color) {
  	//tft_DrawPixel(x, y, color);
  	//if(!buffer) return;
    //if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;
//    int t;
//    switch(rotation) {
//    case 1:
//    	t = x;
//    	x = gfxWIDTH  - 1 - y;
//    	y = t;
//    	break;
//    case 2:
//    	x = gfxWIDTH  - 1 - x;
//    	y = gfxHEIGHT - 1 - y;
//    	break;
//     case 3:
//     	t = x;
//     	x = y;
//     	y = gfxHEIGHT - 1 - t;
//     	break;
//	}
//	buffer[x + y * gfxWIDTH] = color;
//}

// Bresenham's algorithm - thx wikpedia
void gfx_DrawLine(int x0, int y0, int x1, int y1, int color) {
  	int steep = abs(y1 - y0) > abs(x1 - x0);
  	if (steep) {
    	swap_int16(x0, y0);
    	swap_int16(x1, y1);
  	}

  	if (x0 > x1) {
    	swap_int16(x0, x1);
    	swap_int16(y0, y1);
	}

  	int dx, dy;
  	dx = x1 - x0;
  	dy = abs(y1 - y0);

  	int err = dx / 2;
  	int ystep;

  	if (y0 < y1) ystep = 1; else ystep = -1;

  	for (; x0<=x1; x0++) {
    	if (steep) {
      		gfx_DrawPixel(y0, x0, color);
    	} else {
      		gfx_DrawPixel(x0, y0, color);
    	}
    	err -= dy;
    	if (err < 0) {
      		y0 += ystep;
      		err += dx;
    	}
  	}
}

void gfx_DrawFastVLine(s16 x, s16 y, s16 h, uint color) {
  	// Update in subclasses if desired!
  	//gfx_DrawLine(x, y, x, y+h-1, color); // se usar buffer
  	tft_DrawFastVLine(x, y, h, color);
}

void gfx_DrawFastHLine(s16 x, s16 y, s16 w, uint color) {
  	// Update in subclasses if desired!
  	//gfx_DrawLine(x, y, x+w-1, y, color); // se usar buffer

  	tft_DrawFastHLine(x, y, w, color);
}

void gfx_FillRect(int x, int y, int w, int h, uint color) {
  	// Update in subclasses if desired!
  	int i; for (i=x; i<x+w; i++) gfx_DrawFastVLine(i, y, h, color);
  	// tft_FillRect(x, y, w, h, color); // se usar buffer
}

void gfx_FillScreen(uint color) {
  	 gfx_FillRect(0, 0, _width, _height, color);
  	 // tft_FillRect(0, 0, _width,_heighth, color); // se usar buffer
	//  if(buffer) {
	//    uint16_t bytes = ((WIDTH + 7) / 8) * HEIGHT;
	//    memset(buffer, color ? 0xFF : 0x00, bytes);
	//  }
}

// Draw a rectangle
void gfx_DrawRect(int x, int y, int w, int h, uint color) {
  	gfx_DrawFastHLine(x, y, w, color);
  	gfx_DrawFastHLine(x, y+h-1, w, color);
  	gfx_DrawFastVLine(x, y, h, color);
  	gfx_DrawFastVLine(x+w-1, y, h, color);
}

// Draw a triangle
void gfx_DrawTriangle(int x0, int y0, int x1, int y1, int x2, int y2, uint color) {
  	gfx_DrawLine(x0, y0, x1, y1, color);
  	gfx_DrawLine(x1, y1, x2, y2, color);
  	gfx_DrawLine(x2, y2, x0, y0, color);
}

void gfx_FillTriangle(int x0, int y0, int x1, int y1, int x2, int y2, uint color) {
  	int a, b, y, last;

  	// Sort coordinates by Y order (y2 >= y1 >= y0)
  	if (y0 > y1) {
    	swap_int16(y0, y1); swap_int16(x0, x1);
  	}
  	if (y1 > y2) {
    	swap_int16(y2, y1); swap_int16(x2, x1);
  	}
  	if (y0 > y1) {
    	swap_int16(y0, y1); swap_int16(x0, x1);
  	}

  	if(y0 == y2) { // Handle awkward all-on-same-line case as its own thing
    	a = b = x0;
    	if(x1 < a)      a = x1;
    	else if(x1 > b) b = x1;
    	if(x2 < a)      a = x2;
    	else if(x2 > b) b = x2;
    	gfx_DrawFastHLine(a, y0, b-a+1, color);
    	return;
  	}

  	int
    	dx01 = x1 - x0,
    	dy01 = y1 - y0,
    	dx02 = x2 - x0,
    	dy02 = y2 - y0,
    	dx12 = x2 - x1,
    	dy12 = y2 - y1;
  	s32
    	sa   = 0,
    	sb   = 0;

  	// For upper part of triangle, find scanline crossings for segments
  	// 0-1 and 0-2.  If y1=y2 (flat-bottomed triangle), the scanline y1
  	// is included here (and second loop will be skipped, avoiding a /0
  	// error there), otherwise scanline y1 is skipped here and handled
  	// in the second loop...which also avoids a /0 error here if y0=y1
  	// (flat-topped triangle).
  	if(y1 == y2) last = y1;   // Include y1 scanline
  	else         last = y1-1; // Skip it

  	for(y=y0; y<=last; y++) {
    	a   = x0 + sa / dy01;
    	b   = x0 + sb / dy02;
    	sa += dx01;
    	sb += dx02;
    	if(a > b) swap_int16(a,b);
    	gfx_DrawFastHLine(a, y, b-a+1, color);
  	}

  	// For lower part of triangle, find scanline crossings for segments
  	// 0-2 and 1-2.  This loop is skipped if y1=y2.
  	sa = dx12 * (y - y1);
  	sb = dx02 * (y - y0);
  	for(; y<=y2; y++) {
    	a   = x1 + sa / dy12;
    	b   = x0 + sb / dy02;
    	sa += dx12;
    	sb += dx02;

    	if(a > b) swap_int16(a,b);
    	gfx_DrawFastHLine(a, y, b-a+1, color);
  	}
}

// Draw a circle outline
void gfx_DrawCircle(int x0, int y0, int r, uint color) {
  	int f = 1 - r;
 	int ddF_x = 1;
  	int ddF_y = -2 * r;
  	int x = 0;
  	int y = r;

  	gfx_DrawPixel(x0  , y0+r, color);
  	gfx_DrawPixel(x0  , y0-r, color);
  	gfx_DrawPixel(x0+r, y0  , color);
  	gfx_DrawPixel(x0-r, y0  , color);

  	while (x<y) {
  		if (f >= 0) {
      		y--;
      		ddF_y += 2;
      		f += ddF_y;
    	}
    	x++;
    	ddF_x += 2;
    	f += ddF_x;

    	gfx_DrawPixel(x0 + x, y0 + y, color);
    	gfx_DrawPixel(x0 - x, y0 + y, color);
    	gfx_DrawPixel(x0 + x, y0 - y, color);
    	gfx_DrawPixel(x0 - x, y0 - y, color);
    	gfx_DrawPixel(x0 + y, y0 + x, color);
    	gfx_DrawPixel(x0 - y, y0 + x, color);
    	gfx_DrawPixel(x0 + y, y0 - x, color);
    	gfx_DrawPixel(x0 - y, y0 - x, color);
  	}
}

void gfx_DrawCircleHelper( int x0, int y0, int r, uint cornername, uint color) {
  	int f     = 1 - r;
  	int ddF_x = 1;
  	int ddF_y = -2 * r;
  	int x     = 0;
  	int y     = r;

  	while (x<y) {
    	if (f >= 0) {
      		y--;
      		ddF_y += 2;
      		f     += ddF_y;
    	}
    	x++;
    	ddF_x += 2;
    	f     += ddF_x;
    	if (cornername & 0x4) {
      		gfx_DrawPixel(x0 + x, y0 + y, color);
      		gfx_DrawPixel(x0 + y, y0 + x, color);
    	}
    	if (cornername & 0x2) {
      		gfx_DrawPixel(x0 + x, y0 - y, color);
      		gfx_DrawPixel(x0 + y, y0 - x, color);
    	}
    	if (cornername & 0x8) {
      		gfx_DrawPixel(x0 - y, y0 + x, color);
      		gfx_DrawPixel(x0 - x, y0 + y, color);
    	}
    	if (cornername & 0x1) {
      		gfx_DrawPixel(x0 - y, y0 - x, color);
      		gfx_DrawPixel(x0 - x, y0 - y, color);
    	}
  	}
}

void gfx_FillCircleHelper(int x0, int y0, int r, uint cornername, int delta, uint color) {
  	int f     = 1 - r;
  	int ddF_x = 1;
  	int ddF_y = -2 * r;
  	int x     = 0;
  	int y     = r;

  	while (x<y) {
    	if (f >= 0) {
      		y--;
      		ddF_y += 2;
      		f     += ddF_y;
    	}
    	x++;
    	ddF_x += 2;
    	f     += ddF_x;

    	if (cornername & 0x1) {
      		gfx_DrawFastVLine(x0+x, y0-y, 2*y+1+delta, color);
      		gfx_DrawFastVLine(x0+y, y0-x, 2*x+1+delta, color);
    	}
    	if (cornername & 0x2) {
      		gfx_DrawFastVLine(x0-x, y0-y, 2*y+1+delta, color);
      		gfx_DrawFastVLine(x0-y, y0-x, 2*x+1+delta, color);
    	}
  	}
}

void gfx_FillCircle(int x0, int y0, int r, uint color) {
  	gfx_DrawFastVLine(x0, y0-r, 2*r+1, color);
  	gfx_FillCircleHelper(x0, y0, r, 3, 0, color);
}

// Draw a rounded rectangle
void gfx_DrawRoundRect(int x, int y, int w, int h, int r, uint color) {
  	// smarter version
  	gfx_DrawFastHLine(x+r  , y    , w-2*r, color); // Top
  	gfx_DrawFastHLine(x+r  , y+h-1, w-2*r, color); // Bottom
  	gfx_DrawFastVLine(x    , y+r  , h-2*r, color); // Left
  	gfx_DrawFastVLine(x+w-1, y+r  , h-2*r, color); // Right
  	// draw four corners
  	gfx_DrawCircleHelper(x+r    , y+r    , r, 1, color);
  	gfx_DrawCircleHelper(x+w-r-1, y+r    , r, 2, color);
  	gfx_DrawCircleHelper(x+w-r-1, y+h-r-1, r, 4, color);
  	gfx_DrawCircleHelper(x+r    , y+h-r-1, r, 8, color);
}

// Fill a rounded rectangle
void gfx_FillRoundRect(int x, int y, int w, int h, int r, uint color) {
  	// smarter version
  	gfx_FillRect(x+r, y, w-2*r, h, color);

  	// draw four corners
  	gfx_FillCircleHelper(x+w-r-1, y+r, r, 1, h-2*r-1, color);
  	gfx_FillCircleHelper(x+r    , y+r, r, 2, h-2*r-1, color);
}


// Draw a 1-bit image (bitmap) at the specified (x,y) position from the
// provided bitmap buffer (must be PROGMEM memory) using the specified
// foreground color (unset bits are transparent).
//void Adafruit_GFX::drawBitmap(int x, int y,
// const u8 *bitmap, int w, int h, uint color) {
//
//  int i, j, byteWidth = (w + 7) / 8;
//  u8 byte;
//
//  for(j=0; j<h; j++) {
//    for(i=0; i<w; i++) {
//      if(i & 7) byte <<= 1;
//      else      byte   = (bitmap + j * byteWidth + i / 8);
//      if(byte & 0x80) gfx_DrawPixel(x+i, y+j, color);
//    }
//  }
//}

// Draw a 1-bit image (bitmap) at the specified (x,y) position from the
// provided bitmap buffer (must be PROGMEM memory) using the specified
// foreground (for set bits) and background (for clear bits) colors.
//void Adafruit_GFX::drawBitmap(int x, int y,
// const u8 *bitmap, int w, int h, uint color, uint bg) {
//
//  int i, j, byteWidth = (w + 7) / 8;
//  u8 byte;
//
//  for(j=0; j<h; j++) {
//    for(i=0; i<w; i++ ) {
//      if(i & 7) byte <<= 1;
//      else      byte   = (bitmap + j * byteWidth + i / 8);
//      if(byte & 0x80) gfx_DrawPixel(x+i, y+j, color);
//      else            gfx_DrawPixel(x+i, y+j, bg);
//    }
//  }
//}

//// drawBitmap() variant for RAM-resident (not PROGMEM) bitmaps.
//void Adafruit_GFX::drawBitmap(int x, int y,
// u8 *bitmap, int w, int h, uint color) {
//
//  int i, j, byteWidth = (w + 7) / 8;
//  u8 byte;
//
//  for(j=0; j<h; j++) {
//    for(i=0; i<w; i++ ) {
//      if(i & 7) byte <<= 1;
//      else      byte   = bitmap[j * byteWidth + i / 8];
//      if(byte & 0x80) gfx_DrawPixel(x+i, y+j, color);
//    }
//  }
//}
//
//// drawBitmap() variant w/background for RAM-resident (not PROGMEM) bitmaps.
//void Adafruit_GFX::drawBitmap(int x, int y,
// u8 *bitmap, int w, int h, uint color, uint bg) {
//
//  int i, j, byteWidth = (w + 7) / 8;
//  u8 byte;
//
//  for(j=0; j<h; j++) {
//    for(i=0; i<w; i++ ) {
//      if(i & 7) byte <<= 1;
//      else      byte   = bitmap[j * byteWidth + i / 8];
//      if(byte & 0x80) gfx_DrawPixel(x+i, y+j, color);
//      else            gfx_DrawPixel(x+i, y+j, bg);
//    }
//  }
//}
//
////Draw XBitMap Files (*.xbm), exported from GIMP,
////Usage: Export from GIMP to *.xbm, rename *.xbm to *.c and open in editor.
////C Array can be directly used with this function
//void Adafruit_GFX::drawXBitmap(int x, int y,
// const u8 *bitmap, int w, int h, uint color) {
//
//  int i, j, byteWidth = (w + 7) / 8;
//  u8 byte;
//
//  for(j=0; j<h; j++) {
//    for(i=0; i<w; i++ ) {
//      if(i & 7) byte >>= 1;
//      else      byte   = (bitmap + j * byteWidth + i / 8);
//      if(byte & 0x01) gfx_DrawPixel(x+i, y+j, color);
//    }
//  }
//}

/***************************************************************************/
// code for the GFX button UI element

//Adafruit_GFX_Button::Adafruit_GFX_Button(void) {
//  _gfx = 0;
//}
//
//void Adafruit_GFX_Button::initButton(
// Adafruit_GFX *gfx, int x, int y, u8 w, u8 h,
// uint outline, uint fill, uint textcolor,
// char *label, u8 textsize)
//{
//  _x            = x;
//  _y            = y;
//  _w            = w;
//  _h            = h;
//  _outlinecolor = outline;
//  _fillcolor    = fill;
//  _textcolor    = textcolor;
//  _textsize     = textsize;
//  _gfx          = gfx;
//  strncpy(_label, label, 9);
//  _label[9] = 0;
//}
//
//void Adafruit_GFX_Button::drawButton(boolean inverted) {
//  uint fill, outline, text;
//
//  if(!inverted) {
//    fill    = _fillcolor;
//    outline = _outlinecolor;
//    text    = _textcolor;
//  } else {
//    fill    = _textcolor;
//    outline = _outlinecolor;
//    text    = _fillcolor;
//  }
//
//  _gfx->fillRoundRect(_x - (_w/2), _y - (_h/2), _w, _h, min(_w,_h)/4, fill);
//  _gfx->drawRoundRect(_x - (_w/2), _y - (_h/2), _w, _h, min(_w,_h)/4, outline);
//
//  _gfx->setCursor(_x - strlen(_label)*3*_textsize, _y-4*_textsize);
//  _gfx->setTextColor(text);
//  _gfx->setTextSize(_textsize);
//  _gfx->print(_label);
//}
//
//boolean Adafruit_GFX_Button::contains(int x, int y) {
//  if ((x < (_x - _w/2)) || (x > (_x + _w/2))) return false;
//  if ((y < (_y - _h/2)) || (y > (_y + _h/2))) return false;
//  return true;
//}
//
//void Adafruit_GFX_Button::press(boolean p) {
//  laststate = currstate;
//  currstate = p;
//}
//
//boolean Adafruit_GFX_Button::isPressed() { return currstate; }
//boolean Adafruit_GFX_Button::justPressed() { return (currstate && !laststate); }
//boolean Adafruit_GFX_Button::justReleased() { return (!currstate && laststate); }





//##################################################################################################################
// FONTS
//##################################################################################################################
//#include ""
void gfx_SetCursor(int x, int y) {
  	cursor_x = x;
  	cursor_y = y;
}

int gfx_GetCursorX(void) {
  	return cursor_x;
}

int gfx_GetCursorY(void) {
  	return cursor_y;
}

void gfx_SetTextSize(int s) {
  	textsize = (s > 0) ? s : 1;
}

//void Adafruit_GFX::setTextColor(uint c) {
//  // For 'transparent' background, we'll set the bg
//  // to the same as fg instead of using a flag
//  textcolor = textbgcolor = c;
//}

void gfx_SetTextColor(uint c) {
  	textcolor   = c;
}

//void gfx_SetTextBgColor(uint c) {
//  	textbgcolor = c;
//}

void gfx_SetTextWrap(int w) {
  	wrap = w;
}

// Enable (or disable) Code Page 437-compatible charset.
// There was an error in glcdfont.c for the longest time -- one character
// (#176, the 'light shade' block) was missing -- this threw off the index
// of every character that followed it.  But a TON of code has been written
// with the erroneous character indices.  By default, the library uses the
// original 'wrong' behavior and old sketches will still work.  Pass 'true'
// to this function to use correct CP437 character values in your code.
void gfx_cp437(int x) {
  	_cp437 = x;
}

int gfx_PutChar(n16 ch) {
   	if(ch == '\n') {
   		cursor_x  = 0;
   		cursor_y += (int)textsize * (u8)(gfxFont->yAdvance);
   	} else if(ch != '\r') {
   		u8 first = gfxFont->first;
   		if((ch >= first) && (ch <= (u8)(gfxFont->last))) {
      		u8 c2 = ch - gfxFont->first;
        	//tGFXglyph* glyph = &gfxFont->glyph[c2];
        	const tGFXglyph* glyph = &gfxFont->glyph[c2];
        	u8 w = glyph->width, h = glyph->height;

        	if((w > 0) && (h > 0)) { // Is there an associated bitmap?
          		int xo = glyph->xOffset; // sic
          		if(wrap && ((cursor_x + textsize * (xo + w)) >= _width)) {
            		// Drawing character would go off right edge; wrap to new line
            		cursor_x  = 0;
            		cursor_y += (int)textsize * (u8)(gfxFont->yAdvance);
          		}
          		gfx_DrawChar(cursor_x, cursor_y, ch, textcolor, textsize);
        	}
        	cursor_x += (glyph->xAdvance) * (int)textsize;
      	}
   	}
  	return pdPASS;
}

// Draw a character
void gfx_DrawChar(int x, int y, unsigned char c, uint color, uint size) {
  	if(!gfxFont) return;

    // Character is assumed previously filtered by write() to eliminate
    // newlines, returns, non-printable characters, etc.  Calling drawChar()
    // directly with 'bad' characters of font may cause mayhem!

    c -= gfxFont->first;
	const tGFXglyph* glyph = &gfxFont->glyph[c];
    const u8* bitmap = gfxFont->bitmap;
    uint bo = glyph->bitmapOffset;
    u8  w  = glyph->width,
        h  = glyph->height;

    s8   xo = glyph->xOffset,
         yo = glyph->yOffset;
    u8  xx, yy, bits=0, bit = 0;
    int  xo16=0, yo16=0;

    if(size > 1) {
      	xo16 = xo;
      	yo16 = yo;
    }

    // Todo: Add character clipping here

    // NOTE: THERE IS NO 'BACKGROUND' COLOR OPTION ON CUSTOM FONTS.
    // THIS IS ON PURPOSE AND BY DESIGN.  The background color feature
    // has typically been used with the 'classic' font to overwrite old
    // screen contents with new data.  This ONLY works because the
    // characters are a uniform size; it's not a sensible thing to do with
    // proportionally-spaced fonts with glyphs of varying sizes (and that
    // may overlap).  To replace previously-drawn text when using a custom
    // font, use the getTextBounds() function to determine the smallest
    // rectangle encompassing a string, erase the area with fillRect(),
    // then draw new text.  This WILL infortunately 'blink' the text, but
    // is unavoidable.  Drawing 'background' pixels will NOT fix this,
    // only creates a new set of problems.  Have an idea to work around
    // this (a canvas object type for MCUs that can afford the RAM and
    // displays supporting setAddrWindow() and pushColors()), but haven't
    // implemented this yet.

	for(yy=0; yy<h; yy++) {
      	for(xx=0; xx<w; xx++) {
        	if(!(bit++ & 7)) {
          		bits = bitmap[bo++];
        	}
        	if(bits & 0x80) {
          		if(size == 1) {
            		gfx_DrawPixel(x+xo+xx, y+yo+yy, color);
          		} else {
            		gfx_FillRect(x+(xo16+xx)*size, y+(yo16+yy)*size, size, size, color);
          		}
        	}
        	bits <<= 1;
      	}
    }
}

void gfx_SetFont(tGFXfont *f) {
//  if(f) {          // Font struct pointer passed in?
//    if(!gfxFont) { // And no current font struct?
//      // Switching from classic to new font behavior.
//      // Move cursor pos down 6 pixels so it's on baseline.
//      cursor_y += 6;
//    }
//  } else if(gfxFont) { // NULL passed.  Current font struct defined?
//    // Switching from new to classic font behavior.
//    // Move cursor pos up 6 pixels so it's at top-left of char.
//    cursor_y -= 6;
//  }
  	gfxFont = (tGFXfont*)f;
}

//
//// Pass string and a cursor position, returns UL corner and W,H.
//void Adafruit_GFX::getTextBounds(char *str, int x, int y,
// int *x1, int *y1, uint *w, uint *h) {
//  u8 c; // Current character
//
//  *x1 = x;
//  *y1 = y;
//  *w  = *h = 0;
//
//  if(gfxFont) {
//
//    tGFXglyph *glyph;
//    u8   first = gfxFont->first,
//              last  = gfxFont->last,
//              gw, gh, xa;
//    int8_t    xo, yo;
//    int   minx = _width, miny = _height, maxx = -1, maxy = -1,
//              gx1, gy1, gx2, gy2, ts = (int)textsize,
//              ya = ts * (u8)gfxFont->yAdvance;
//
//    while((c = *str++)) {
//      if(c != '\n') { // Not a newline
//        if(c != '\r') { // Not a carriage return, is normal char
//          if((c >= first) && (c <= last)) { // Char present in current font
//            c    -= first;
//            glyph = &(((tGFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]);
//            gw    = glyph->width;
//            gh    = glyph->height;
//            xa    = glyph->xAdvance;
//            xo    = glyph->xOffset;
//            yo    = &glyph->yOffset;
//            if(wrap && ((x + (((int)xo + gw) * ts)) >= _width)) {
//              // Line wrap
//              x  = 0;  // Reset x to 0
//              y += ya; // Advance y by 1 line
//            }
//            gx1 = x   + xo * ts;
//            gy1 = y   + yo * ts;
//            gx2 = gx1 + gw * ts - 1;
//            gy2 = gy1 + gh * ts - 1;
//            if(gx1 < minx) minx = gx1;
//            if(gy1 < miny) miny = gy1;
//            if(gx2 > maxx) maxx = gx2;
//            if(gy2 > maxy) maxy = gy2;
//            x += xa * ts;
//          }
//        } // Carriage return = do nothing
//      } else { // Newline
//        x  = 0;  // Reset x
//        y += ya; // Advance y by 1 line
//      }
//    }
//    // End of string
//    *x1 = minx;
//    *y1 = miny;
//    if(maxx >= minx) *w  = maxx - minx + 1;
//    if(maxy >= miny) *h  = maxy - miny + 1;
//
//  } else { // Default font
//
//    uint lineWidth = 0, maxWidth = 0; // Width of current, all lines
//
//    while((c = *str++)) {
//      if(c != '\n') { // Not a newline
//        if(c != '\r') { // Not a carriage return, is normal char
//          if(wrap && ((x + textsize * 6) >= _width)) {
//            x  = 0;            // Reset x to 0
//            y += textsize * 8; // Advance y by 1 line
//            if(lineWidth > maxWidth) maxWidth = lineWidth; // Save widest line
//            lineWidth  = textsize * 6; // First char on new line
//          } else { // No line wrap, just keep incrementing X
//            lineWidth += textsize * 6; // Includes interchar x gap
//          }
//        } // Carriage return = do nothing
//      } else { // Newline
//        x  = 0;            // Reset x to 0
//        y += textsize * 8; // Advance y by 1 line
//        if(lineWidth > maxWidth) maxWidth = lineWidth; // Save widest line
//        lineWidth = 0;     // Reset lineWidth for new line
//      }
//    }
//    // End of string
//    if(lineWidth) y += textsize * 8; // Add height of last (or only) line
//    if(lineWidth > maxWidth) maxWidth = lineWidth; // Is the last or only line the widest?
//    *w = maxWidth - 1;               // Don't include last interchar x gap
//    *h = y - *y1;
//
//  } // End classic vs custom font
//}
//
//// Same as above, but for PROGMEM strings
//void Adafruit_GFX::getTextBounds(const __FlashStringHelper *str,
// int x, int y, int *x1, int *y1, uint *w, uint *h) {
//  u8 *s = (u8 *)str, c;
//
//  *x1 = x;
//  *y1 = y;
//  *w  = *h = 0;
//
//  if(gfxFont) {
//
//    tGFXglyph *glyph;
//    u8   first = gfxFont->first,
//              last  = gfxFont->last,
//              gw, gh, xa;
//    int8_t    xo, yo;
//    int   minx = _width, miny = _height, maxx = -1, maxy = -1,
//              gx1, gy1, gx2, gy2, ts = (int)textsize,
//              ya = ts * (u8)gfxFont->yAdvance;
//
//    while((c = s++)) {
//      if(c != '\n') { // Not a newline
//        if(c != '\r') { // Not a carriage return, is normal char
//          if((c >= first) && (c <= last)) { // Char present in current font
//            c    -= first;
//            glyph = &(((tGFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]);
//            gw    = glyph->width;
//            gh    = glyph->height;
//            xa    = glyph->xAdvance;
//            xo    = glyph->xOffset;
//            yo    = glyph->yOffset;
//            if(wrap && ((x + (((int)xo + gw) * ts)) >= _width)) {
//              // Line wrap
//              x  = 0;  // Reset x to 0
//              y += ya; // Advance y by 1 line
//            }
//            gx1 = x   + xo * ts;
//            gy1 = y   + yo * ts;
//            gx2 = gx1 + gw * ts - 1;
//            gy2 = gy1 + gh * ts - 1;
//            if(gx1 < minx) minx = gx1;
//            if(gy1 < miny) miny = gy1;
//            if(gx2 > maxx) maxx = gx2;
//            if(gy2 > maxy) maxy = gy2;
//            x += xa * ts;
//          }
//        } // Carriage return = do nothing
//      } else { // Newline
//        x  = 0;  // Reset x
//        y += ya; // Advance y by 1 line
//      }
//    }
//    // End of string
//    *x1 = minx;
//    *y1 = miny;
//    if(maxx >= minx) *w  = maxx - minx + 1;
//    if(maxy >= miny) *h  = maxy - miny + 1;
//
//  } else { // Default font
//
//    uint lineWidth = 0, maxWidth = 0; // Width of current, all lines
//
//    while((c = s++)) {
//      if(c != '\n') { // Not a newline
//        if(c != '\r') { // Not a carriage return, is normal char
//          if(wrap && ((x + textsize * 6) >= _width)) {
//            x  = 0;            // Reset x to 0
//            y += textsize * 8; // Advance y by 1 line
//            if(lineWidth > maxWidth) maxWidth = lineWidth; // Save widest line
//            lineWidth  = textsize * 6; // First char on new line
//          } else { // No line wrap, just keep incrementing X
//            lineWidth += textsize * 6; // Includes interchar x gap
//          }
//        } // Carriage return = do nothing
//      } else { // Newline
//        x  = 0;            // Reset x to 0
//        y += textsize * 8; // Advance y by 1 line
//        if(lineWidth > maxWidth) maxWidth = lineWidth; // Save widest line
//        lineWidth = 0;     // Reset lineWidth for new line
//      }
//    }
//    // End of string
//    if(lineWidth) y += textsize * 8; // Add height of last (or only) line
//    if(lineWidth > maxWidth) maxWidth = lineWidth; // Is the last or only line the widest?
//    *w = maxWidth - 1;               // Don't include last interchar x gap
//    *h = y - *y1;
//
//  } // End classic vs custom font
//}


#if (TFT_USE_PRINTF == pdON)
#include "stdio_uc.h"
static uint devicePrintf = 0;
void gfx_printfInit(uint dev) {
	devicePrintf = dev;
	rprintf_RegisterDev(dev, gfx_PutChar);	// Anexa a função ao printf
}

// faz o mesmo que rprintf, porém acrescenta espaços vazios para preencher toda a linha,
//	apagando os caracteres impressos anteriormente
void gfx_printf(const cpchar fmt, ...) {
	string s;
	tPrint output;

	output.device = 0;
	output.buf = s;					// Sinaliza qual buffer para armazenar a formatação de string. Também sinaliza que é uma formatação de string e não uma impressão em dipositivo
	output.isSformat = 1;			// Sinaliza que é um sformat

	va_list args;					// Cria var para captura de argumentos (fmt) no stack da chamada de função
	va_start(args, fmt);			// Captura os argumentos após fmt
	doprint(&output, fmt, args);	// Faz a formatação da string com ftm e args e manda imprimir
	va_end(args);					// Desmonta args

	rprintf(devicePrintf, "%s", s);
}
#endif
